package org.simpleframework.inject;

import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.BeanContainer;
import org.simpleframework.inject.annotation.Autowired;
import org.simpleframework.util.ClassUtil;
import org.simpleframework.util.ValidationUtil;

import java.io.File;
import java.lang.reflect.Field;
import java.util.Set;

/**
 * @author linchong
 * @version 1.0
 * @Date: 2022-05-22 19:42
 * @Description: DependencyInjector$
 */
@Slf4j
public class DependencyInjector {

	/**
	 * Bean容器
	 */
	private BeanContainer beanContainer;

	public DependencyInjector(){
		this.beanContainer = BeanContainer.getInstance();
	}

	/**
	 * 执行IOC,对容器中的class对象做依赖注入处理
	 */
	public void doIoc(){
		//1.遍历Bean容器中的所有class对象
		if(ValidationUtil.isEmpty(beanContainer.getClasses())){
			log.warn("empty classset in BeanContainer");
			return;
		}
		for(Class<?> clazz:beanContainer.getClasses()){
			//2.遍历class对象的所有成员变量
			Field[] fields = clazz.getDeclaredFields();
			if(ValidationUtil.isEmpty(fields)){
				continue;
			}
			//3.找出被Autowired标记的成员变量
			for(Field field:fields){
				if(field.isAnnotationPresent(Autowired.class)){
					Autowired autowired = field.getAnnotation(Autowired.class);
					String autowiredValue = autowired.value();
					//4.获取这些成员变量的类型
					Class<?> fieldClazz = field.getType();
					//5.获取这些成员变量的类型在容器里对应的实例
					Object fieldValue = getFieldInstance(fieldClazz,autowiredValue);
					if(fieldValue == null){
						throw new RuntimeException("unable to inject relevant type,target fieldClass is :"+fieldClazz.getName());
					}else{
					//6.通过反射将对应的成员变量实例注入到成员变量
						Object targetBean = beanContainer.getBean(clazz);
						ClassUtil.setField(field,targetBean,fieldValue,true);
					}
				}
			}
		}
	}


	/**
	 * 根据Class在beanContainer里获取其实例或者实现类
	 * @param fieldClazz
	 * @return
	 */
	private Object getFieldInstance(Class<?> fieldClazz,String autowiredValue) {
		Object fieldValue = beanContainer.getBean(fieldClazz);
		//类实现
		if(fieldValue != null){
			return fieldValue;
		}
		//接口实现
		else{
			Class<?> implementedClass = getImplementedClass(fieldClazz,autowiredValue);
			if(implementedClass != null){
				return beanContainer.getBean(implementedClass);
			}else{
				return null;
			}
		}
	}

	/**
	 * 获取接口实现类
	 * @param fieldClazz
	 * @return
	 */
	private Class<?> getImplementedClass(Class<?> fieldClazz,String autowiredValue) {
		Set<Class<?>> classSet = beanContainer.getClassesBySuper(fieldClazz);
		if(!ValidationUtil.isEmpty(classSet)){
			if(ValidationUtil.isEmpty(autowiredValue)){
				if(classSet.size() == 1) return classSet.iterator().next();
				else {
					//如果多与两个实现类且用户没有指定其中的一个实例，则抛出异常
					throw new RuntimeException("multiple implemented classes for "+fieldClazz.getName()+",please pick one,Autowired is "+autowiredValue);
				}
			}else{
				for (Class<?> clazz : classSet) {
					if(autowiredValue.equals(clazz.getSimpleName())){
						return clazz;
					}
				}
			}
		}
		return null;
	}
}
